package com.hp.bon.sgw.wh.mml;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import com.hp.bon.sgw.wh.mml.common.MMLConstants;
import com.hp.bon.sgw.wh.mml.handler.MMLOutputHandler;
import com.hp.bon.sgw.wh.mml.repositories.PropertyRepository;

import ch.unifr.nio.framework.AbstractClientSocketChannelHandler;
import ch.unifr.nio.framework.Dispatcher;
import ch.unifr.nio.framework.transform.ByteBufferToStringTransformer;

public class VCClient extends AbstractClientSocketChannelHandler{
	
	private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(VCClient.class.getName());
	//private static final java.util.logging.Logger nioLogger = Logger.getLogger(VCClient.class.getName());
	
	private String serverHost;
	private int serverPort;
	private Dispatcher dispatcher = null;
	
	private AtomicInteger vcConnectionStatus = new AtomicInteger(MMLConstants.VC_CONN_IDLE);
	//private AtomicBoolean isConnection = new AtomicBoolean(false);
	
	private static VCClient vcClient = null;
	
	public static VCClient instance(){
		return VCClient.newInstance();
	}
	
	public static VCClient newInstance(){
		if(vcClient==null){
			vcClient = new VCClient();
		}
		return vcClient;
	}
	
	public static void teardownVCClient(){
		vcClient = null;
	}
	
	private VCClient(){
	}
	
	public boolean setupVCClient() {
		boolean ret = true;
		
		if(vcConnectionStatus.equals(MMLConstants.VC_CONN_OK)){
			return ret;
		}
		vcConnectionStatus.set(MMLConstants.VC_CONN_IDLE);
		
		ByteBufferToStringTransformer byteBufferToStringTransformer = new ByteBufferToStringTransformer();
		byteBufferToStringTransformer.setNextForwarder(new VCClientTransformer());
		channelReader.setNextForwarder(byteBufferToStringTransformer);
		try {
			dispatcher = new Dispatcher();
			dispatcher.start();
			serverHost = PropertyRepository.getVCHost();
			serverPort = PropertyRepository.getVCPort();
			logger.info("VCHost=[" + serverHost + "], VCPort=[" + serverPort + "]");
			dispatcher.registerClientSocketChannelHandler(serverHost, serverPort, this);
			int times = 0;
			while (getConnectionStatus() == MMLConstants.VC_CONN_IDLE) {
				logger.info("waitting for zbvc connection...");
				if(times > 5){
					logger.warn("waitting for zbvc connection[=timeout]");
					break;
				}
				Thread.sleep(1000);
				times++;
			}
			logger.info("setupVCClient finish.");
		} catch (IOException e) {
			ret = false;
			logger.warn("setupVCClient", e);
		} catch (InterruptedException e) {
			logger.warn("setupVCClient sleep error: ", e);
		}		
		return ret;
	}
	
	public int getConnectionStatus() {
		return vcConnectionStatus.intValue();
	}
	
	@Override
	public void connectSucceeded() {
		vcConnectionStatus.set(MMLConstants.VC_CONN_OK);
		new MMLOutputHandler(this.channelWriter).start();
		logger.info("VC connect successfully.");
	}
	@Override
	public void connectFailed(IOException exception) {
		vcConnectionStatus.set(MMLConstants.VC_CONN_FAIL);
		logger.warn("VC connect Failed.", exception);
	}
	@Override
	public void channelException(Exception exception) {
		vcConnectionStatus.set(MMLConstants.VC_CONN_FAIL);
		logger.warn("Connection error ", exception);
	}
	@Override
	public void resolveFailed() {
		vcConnectionStatus.set(MMLConstants.VC_CONN_FAIL);
		logger.warn("Could not resolve \"" + serverHost + "\"");
	}
	@Override
	public void inputClosed() {
		logger.warn("VC server closed the connection \"" + serverHost + "\"");
		if (dispatcher != null) {
			logger.info("dispatcher.closeChannel()");
			try {
				dispatcher.closeChannel();
			} catch (Exception e) {
				logger.warn("dispatcher.closeChannel()", e);
			}
		}
		vcConnectionStatus.set(MMLConstants.VC_CONN_FAIL);
	}
}
